#include <iostream>
#include <cstdio>
#include <unistd.h>
#include <cstring>
#include <sys/types.h>
#include <sys/wait.h>
#include <cstdlib>
#include <sys/stat.h>
#include <sys/fcntl.h>

#define PROMPT_SIZE 1024
#define COMMAND_SIZE 128
#define FORMAT "[%s@%s %s]# "
using namespace std;

int LastPidNode = 0;

//命令行参数表
char* g_argv[COMMAND_SIZE];
int g_argc = 0;


//环境变量表
char* g_env[120];
int g_enc = 0;

//重定向参数配置
#define NON_DIR 0
#define INPUT_DIR 1
#define OUTPUT_DIR 2
#define APPEND_DIR 3

int dir = NON_DIR;
string filename;

char  env[1024];
char  env_value[1024];

//环境变量表配置
void InitEnv()
{
    extern char** environ;
    memset(g_env,0,sizeof(g_env));
    g_enc = 0;
    for(int i = 0; environ[i]; i++)
    {
        g_env[i] = (char*)malloc(strlen(environ[i]+1));
        strcpy(g_env[i],environ[i]);
        g_enc++;
    }
    g_env[g_enc++] =(char*) "name=nihaha";
    g_env[g_enc] = NULL;
    for(int i = 0; g_env[i]; i++)
    {
        putenv(g_env[i]);
    }
    environ = g_env;
}


//1.输出命令行提示符

const char* GetUserName()
{
    char* name = getenv("USER");
    return name == NULL ? "none" : name;
}

const char* GetHostName()
{
    char* name = getenv("HOSTNAME");
    return name == NULL ? "none" : name;
}

const char* GetPWD()
{
    char* pwd = getcwd(env,sizeof(env));
    if(pwd != NULL)
    {
        snprintf(env_value,sizeof(env),"PWD=%s",pwd);
        putenv(env_value);
    }   
    return pwd == NULL ? "" : pwd;
}

const char* GetHomeName()
{
    char* name = getenv("HOME");
    return name == NULL ? "none" : name;
}

string DirName(const char* pwd)
{
#define slash "/"
    string tmp = pwd;
    auto pos = tmp.rfind(slash);
    if(tmp == slash) return slash;
    if(pos == string::npos) return "bug?";
    return tmp.substr(pos+1);
}
void GetPromptLine(char promptline[],int size)
{
   snprintf(promptline,size,FORMAT,GetUserName(),GetHostName(),DirName(GetPWD()).c_str());
}

void CommandLinePrompt()    
{
    char Promptline[PROMPT_SIZE];
    GetPromptLine(Promptline,sizeof(Promptline));
    printf("%s",Promptline);
    fflush(stdout);
}

//2.获取用户输入命令
bool GetCommandLine(char* out,int size)
{
    char* com = fgets(out,size,stdin);
    if(com == NULL) return false;
    out[strlen(out)-1] = 0;
    return true;
}

//3.解析用户输入指令
//"ls -l -a" "ls" "-l" "-a"
void CommandTranslate(char* commandline)
{
#define seg " "
    g_argc = 0;
    g_argv[g_argc++] = strtok(commandline,seg);
    while((bool)(g_argv[g_argc++] = strtok(NULL,seg)));
    g_argc--;
}

//4.判断是否为内建命令

void Cd()
{
    if(g_argc == 1)
    {
        chdir(GetHomeName());
    }else if (g_argc == 2)
    {
        string tmp = g_argv[1];
        chdir(tmp.c_str());
    }
}

void Echo()
{
    if(g_argc == 2)
    {
        string tmp = g_argv[1];
        if(tmp == "$?")
        {
            cout << LastPidNode << endl; 
        }else if (tmp[0] == '$')
        {
            string Env_value = tmp.substr(1);
            cout << getenv(Env_value.c_str()) << endl;
        }else
        {
            cout << tmp << endl;
        }
    }
} 

bool CheckAndBulidIn()
{
    string tmp = g_argv[0];
    if(tmp == "cd")
    {
        Cd();
        return true;
    }
    else if (tmp == "echo")
    {
        Echo();
        return true;
    }
    return false;
}

//5.Execute()
int Execute()
{
    pid_t id = fork();
    if(id == 0)
    {
        if(dir == 0)
        {
        }
        else if (dir == 1)
        {
            int fd = open(filename.c_str(),O_RDONLY);
            dup2(fd,0);
            close(fd);
        }
        else if (dir == 2)
        {
            int fd = open(filename.c_str(),O_CREAT | O_WRONLY | O_TRUNC,0666);
            dup2(fd,1);
            close(fd);
        }
        else if (dir == 3)
        {
            int fd = open(filename.c_str(),O_CREAT | O_WRONLY | O_APPEND,0666);
            dup2(fd,3);
            close(fd);
        }
        execvp(g_argv[0],g_argv);
        cout << "不存在该条指令" << endl;
        exit(1);
    }
    int status = 0;
    LastPidNode = waitpid(id,&status,0);
    return 0;
}

//重定向
void EraseSpace(char* cmd,int& end)
{
    while(isspace(cmd[end]))
    {
        end++;
    }
}
void CheckDir(char* cmd)
{
    dir = NON_DIR;
    filename.clear();
    int start = 0;
    int end = strlen(cmd)-1;
    while(end > start)
    {
        if(cmd[end] == '<')
        {
            cmd[end++] = 0;
            EraseSpace(cmd,end);
            filename = cmd+end;
            dir = INPUT_DIR;
        }
        else if (cmd[end] == '>')
        {
            if(cmd[end-1] == '>')
            {
                cmd[end-1] = 0;
                dir = APPEND_DIR;
            }
            else 
            {
                dir = OUTPUT_DIR;
            }
            cmd[end++] = 0;
            EraseSpace(cmd,end);
            filename = cmd+end;
        }
        else 
        {
            end--;
        }
    }
}

int main()
{
    InitEnv();
    while(true)
    {
        //1.输出命令行提示符
        CommandLinePrompt();
        //2.获取用户输入命令
        char CommandLine[COMMAND_SIZE];
        if(!GetCommandLine(CommandLine,sizeof(CommandLine)))
            continue;
        //重定向
        CheckDir(CommandLine);
        //3.解析用户输入命令
        CommandTranslate(CommandLine);
        //4.判断是否为内建命令
        if(CheckAndBulidIn())
        {
            continue;
        }
        //5.执行
        Execute();
    }
    return 0;
}
